<template>
  <view class="tn-number-box">
    <!-- 减 -->
    <slot name="minus">
      <view
        class="tn-number-box__minus"
        :class="[containerClass('minus')]"
        :style="containerStyle('minus')"
        @touchstart.stop.prevent="handleOperationTouch('minus')"
        @touchend.stop.prevent="clearLongPressTimer"
      >
        <tn-icon icon="reduce"></tn-icon>
      </view>
    </slot>

    <!-- 输入框 -->
    <input
      class="tn-number-box__input"
      :class="[containerClass('input')]"
      :style="containerStyle('input')"
      v-model="numberValue"
      type="digit"
      :disabled="disabled || disabledInput"
      :cursor-spacing="cursorSpacing"
      @blur="handleBlur"
    />

    <!-- 加 -->
    <slot name="plus">
      <view
        class="tn-number-box__plus"
        :class="[containerClass('plus')]"
        :style="containerStyle('plus')"
        @touchstart.stop.prevent="handleOperationTouch('plus')"
        @touchend.stop.prevent="clearLongPressTimer"
      >
        <tn-icon icon="add"></tn-icon>
      </view>
    </slot>
  </view>
</template>

<script lang="ts" setup>
import { numberBoxProps, numberBoxEmits } from '../../../types/tn-number-box'
import { computed, CSSProperties, ref, watch, watchEffect } from 'vue'
import useComponentColor from '../../../libs/hooks/useComponentColor'
import { handleValueWithUnit } from '../../../utils'
import TnIcon from '../../tn-icon/src/Icon.vue'
import { UPDATE_MODEL_EVENT } from '../../../constants'

const props = defineProps(numberBoxProps)
const emits = defineEmits(numberBoxEmits)

// 解析颜色
const { generateColorInfo } = useComponentColor()
let componentColorInfo = generateColorInfo(props?.color || '', props?.bgColor || '')
// 监听颜色变化实时修改颜色对应的属性
watchEffect(() => {
  componentColorInfo = generateColorInfo(props?.color || '', props?.bgColor || '')
})

type ContianerType = 'minus' | 'input' | 'plus'
// 容器样式
const containerStyle = computed<(type: ContianerType) => CSSProperties>(() => {
  return (type: ContianerType) => {
    let style: CSSProperties = {}
    if (type === 'input' && props?.inputWidth) style.width = handleValueWithUnit(props.inputWidth)
    if (props?.inputHeight) {
      style.height = `calc(${handleValueWithUnit(props.inputHeight)} + 18rpx)`
      style.fontSize = handleValueWithUnit(props.inputHeight)
    }
    if (componentColorInfo.style?.color) style.color = componentColorInfo.style.color
    if (componentColorInfo.style?.backgroundColor) style.backgroundColor = componentColorInfo.style.backgroundColor
    return style
  }
})

// 容器对应的类
const containerClass = computed<(type: ContianerType) => string>(() => {
  return (type: ContianerType) => {
    let clazz: string[] = []
    if (props?.disabled
      || (type === 'input' && props?.disabledInput)
      || (type === 'minus' && numberValue.value <= props?.min)
      || (type === 'plus' && numberValue.value >= props?.max)
    ) clazz.push('disabled')
    if (componentColorInfo.class.length > 0) clazz.push(...componentColorInfo.class)
    return clazz.join(' ')
  }
})

// number的值
let numberValue = ref<number>(0)
watch(() => props.modelValue, (value: number) => {
  if (value < props?.min) numberValue.value = props?.min
  else if (value > props?.max) numberValue.value = props?.max
  else numberValue.value = value
}, {
  immediate: true
})

// 处理输入框失去焦点事件
const handleBlur = (e: any) => {
  if (props?.disabled || props?.disabledInput) return
  let value: number = Number(e.detail.value) || props?.min || 0
  if (value < props?.min) value = props?.min
  else if (value > props?.max) value = props?.max

  updateNumberValue(value)
}

// 处理加、减事件
let longPressTimer: number | null = null
const handleOperationTouch = (type: 'minus' | 'plus') => {
  if (props?.disabled) return
  const changeValue = (type: 'minus' | 'plus') => {
    let value = numberValue.value
    const stepValue = props?.step || 0
    if(type === 'minus') {
      value -= stepValue
    } else if (type === 'plus') {
      value += stepValue
    }
    if(value < props?.min) {
      value = props?.min
      props?.longPress && clearLongPressTimer()
    }
    if (value > props?.max) {
      value = props?.max
      props?.longPress && clearLongPressTimer()
    }

    updateNumberValue(value)
  }
  if (props?.longPress) {
    changeValue(type)
    clearLongPressTimer()
    longPressTimer = setInterval(() => {
      changeValue(type)
    }, Number(props?.longPressTime) || 250)
  } else {
    changeValue(type)
  }
}
const clearLongPressTimer = () => {
  if (longPressTimer !== null) {
    clearInterval(longPressTimer)
    longPressTimer = null
  }
}

// 更新number的数值
const updateNumberValue = (value: number) => {
  // 获取step的小数位数
  const stepValue = props?.step || 0
  const stepValueArray: string[] = stepValue.toString().split('.')
  const decimalCount:number = stepValueArray.length > 1 ? stepValueArray[1].length : 0
  value = Number(value.toFixed(decimalCount))
  emits(UPDATE_MODEL_EVENT, value)
  emits('change', value)
}
</script>

<script lang="ts">
export default {
  options: {
    // 在微信小程序中将组件节点渲染为虚拟节点，更加接近Vue组件的表现(不会出现shadow节点下再去创建元素)
    virtualHost: true
  }
}
</script>

<style lang="scss" scoped>
@import '../../../theme.scss';

.tn-number-box {
  display: inline-flex;
  align-items: center;

  &__minus, &__input, &__plus {
    background-color: #E6E6E6;
    font-size: 28rpx;
    height: calc(28rpx + 18rpx);
    line-height: 1;
    padding: 0rpx 14rpx;
    display: flex;
    align-items: center;
    justify-content: center;

    &.disabled {
      opacity: 0.3;
    }
  }
  &__minus {
    margin-right: 4rpx;
  }
  &__plus {
    margin-left: 4rpx;
  }
  &__input {
    min-height: initial;
    text-align: center;
    width: 80rpx;
  }
}
</style>
